package com.seqb.utils;

import com.xuxueli.poi.excel.ExcelExportUtil;
import com.xuxueli.poi.excel.annotation.ExcelField;
import com.xuxueli.poi.excel.annotation.ExcelSheet;
import com.xuxueli.poi.excel.util.FieldReflectionUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * @author lilinshen
 * @title Excel导出工具
 * @description 重写ExcelExportUtil类，实现只有@ExcelField注解的才导出
 * @date 2019/11/12
 */
public class ExcelExportUtils extends ExcelExportUtil {
    private static Logger LOGGERR = LoggerFactory.getLogger(com.xuxueli.poi.excel.ExcelExportUtil.class);

    /**
     * 导出Excel文件到输出流
     */
    public static void exportToFile(List<?> dataList, OutputStream outputStream) {
        // workbook
        Workbook workbook = exportWorkbook(dataList, null);
        try {
            // workbook 2 outputStream
            workbook.write(outputStream);
            // flush
            outputStream.flush();
        } catch (Exception e) {
            LOGGERR.error(e.getMessage(), e);
            throw new RuntimeException(e);
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (Exception e) {
                LOGGERR.error(e.getMessage(), e);
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 导出Excel文件到输出流（指定class）
     */
    public static void exportToFile(List<?> dataList, OutputStream outputStream, Class<?> clazz) {
        // workbook
        Workbook workbook = exportWorkbook(dataList, clazz);
        try {
            // workbook 2 outputStream
            workbook.write(outputStream);
            // flush
            outputStream.flush();
        } catch (Exception e) {
            LOGGERR.error(e.getMessage(), e);
            throw new RuntimeException(e);
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (Exception e) {
                LOGGERR.error(e.getMessage(), e);
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 导出数据到Excel表
     */
    private static Workbook exportWorkbook(List<?> dataList, Class<?> clazz) {
        // sheet
        Class sheetClass = (clazz != null ? clazz : dataList.get(0).getClass());
        ExcelSheet excelSheet = (ExcelSheet) sheetClass.getAnnotation(ExcelSheet.class);
        String sheetName = sheetClass.getSimpleName();
        HSSFColor.HSSFColorPredefined headColor = null;
        if (excelSheet != null) {
            if (excelSheet.name() != null && excelSheet.name().trim().length() > 0) {
                sheetName = excelSheet.name().trim();
            }
            headColor = excelSheet.headColor();
        }

        // 统计出有ExcelField的属性字段
        List<Field> fields = new ArrayList<Field>();
        if (sheetClass.getDeclaredFields() != null && sheetClass.getDeclaredFields().length > 0) {
            Field[] workbook = sheetClass.getDeclaredFields();
            int sheet = workbook.length;
            for (int headStyle = 0; headStyle < sheet; ++headStyle) {
                Field headRow = workbook[headStyle];
                ExcelField rowData = (ExcelField) headRow.getAnnotation(ExcelField.class);
                if (rowData == null) {
                    continue;
                }
                String name = rowData.name().trim();
                if (StringUtils.isEmpty(name)) {
                    continue;
                }
                if (!Modifier.isStatic(headRow.getModifiers())) {
                    fields.add(headRow);
                }
            }
        }
        if (fields == null || fields.size() == 0) {
            throw new RuntimeException(">>>>>>>>>>> xxl-excel error, data field can not be empty.");
        }

        HSSFWorkbook workbook = new HSSFWorkbook();
        Sheet sheet = workbook.createSheet(sheetName);
        CellStyle headStyle = null;
        if (headColor != null) {
            headStyle = workbook.createCellStyle();
            headStyle.setFillForegroundColor(headColor.getIndex());
            headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            headStyle.setFillBackgroundColor(headColor.getIndex());
            headStyle.setAlignment(HorizontalAlignment.CENTER);
            headStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        }
        Row headRow = sheet.createRow(0);
        //是否需要调整宽度
        boolean ifSetWidth = false;
        for (int i = 0; i < fields.size(); i++) {
            headRow.setHeight((short) 500);
            Field field = fields.get(i);
            // 反射出object的属性，是否有@ExcelField注解，没有的不导出
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if (excelField == null) {
                continue;
            }
            // 获取@ExcelField注解的属性name的值，没有的不导出
            String name = excelField.name().trim();
            if (StringUtils.isEmpty(name)) {
                continue;
            }
            String fieldName = excelField != null && excelField.name() != null && excelField.name().trim().length() > 0 ? excelField.name() : field.getName();
            int fieldWidth = (excelField != null) ? excelField.width() : 0;
            Cell cell = headRow.createCell(i, CellType.STRING);
            if (headStyle != null) {
                cell.setCellStyle(headStyle);
            }
            if (fieldWidth > 0) {
                sheet.setColumnWidth(i, fieldWidth * 30);
                ifSetWidth = true;
            }
            cell.setCellValue(String.valueOf(fieldName));
        }
        //填充值到excel表格中
        doFillValue(dataList, workbook, sheet, fields);

        if (!ifSetWidth) {
            for (int i = 0; i < fields.size(); i++) {
                sheet.autoSizeColumn((short) i);
            }
        }
        return workbook;
    }

    /**
     * 填充数据到excel表格中
     */
    private static void doFillValue(List<?> dataList, HSSFWorkbook workbook, Sheet sheet, List<Field> fields) {
        if (dataList == null || dataList.size() == 0) {
            CellStyle emptyStyle = workbook.createCellStyle();
            emptyStyle.setAlignment(HorizontalAlignment.CENTER);
            emptyStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            Row emptyRow = sheet.createRow(1);
            emptyRow.setHeight((short) 400);
            Cell emptyCell = emptyRow.createCell(0);
            emptyCell.setCellStyle(emptyStyle);
            emptyCell.setCellValue("暂无数据");
            sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, fields.size() - 1));
        }
        for (int dataIndex = 0; dataIndex < dataList.size(); dataIndex++) {
            int rowIndex = dataIndex + 1;
            Object rowData = dataList.get(dataIndex);
            Row row = sheet.createRow(rowIndex);
            row.setHeight((short) 400);
            for (int i = 0; i < fields.size(); ++i) {
                Field field = fields.get(i);
                // 反射出object的属性，是否有@ExcelField注解，没有的不导出
                ExcelField excelField = field.getAnnotation(ExcelField.class);
                if (excelField == null) {
                    continue;
                }
                // 获取@ExcelField注解的属性name的值，没有的不导出
                String name = excelField.name().trim();
                if (StringUtils.isEmpty(name)) {
                    continue;
                }
                try {
                    field.setAccessible(true);
                    Object fieldValue = field.get(rowData);
                    String fieldValueString = FieldReflectionUtil.formatValue(field, fieldValue);
                    Cell cell = row.createCell(i, CellType.STRING);
                    cell.setCellValue(fieldValueString);
                } catch (Exception e) {
                    LOGGERR.error(e.getMessage(), e);
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
